package com.spyx.product.service.impl;


import com.atyx.spyx.model.product.SkuAttrValue;
import com.atyx.spyx.model.product.SkuImage;
import com.atyx.spyx.model.product.SkuInfo;
import com.atyx.spyx.model.product.SkuPoster;
import com.atyx.spyx.vo.product.SkuInfoQueryVo;
import com.atyx.spyx.vo.product.SkuInfoVo;
import com.atyx.spyx.vo.product.SkuStockLockVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spyx.common.config.MQConfig;
import com.spyx.common.constant.MqConst;
import com.spyx.common.service.RabbitService;
import com.spyx.constant.RedisConst;
import com.spyx.exception.SpyxException;
import com.spyx.product.mapper.SkuInfoMapper;
import com.spyx.product.service.SkuAttrValueService;
import com.spyx.product.service.SkuImageService;
import com.spyx.product.service.SkuInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spyx.product.service.SkuPosterService;
import com.spyx.result.ResultCodeEnum;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * sku信息 服务实现类
 * </p>
 *
 * @author yhp
 * @since 2024-05-15
 */
@Service
public class SkuInfoServiceImpl extends ServiceImpl<SkuInfoMapper, SkuInfo> implements SkuInfoService {

    @Override
    public IPage<SkuInfo> getInfoList(Page page, SkuInfoQueryVo queryVo) {
        //1.获取模糊查条件
        String skuType = queryVo.getSkuType();
        String keyword = queryVo.getKeyword();
        Long categoryId = queryVo.getCategoryId();
        //2.封装条件
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        if(!StringUtils.isEmpty(skuType)){
            wrapper.eq(SkuInfo::getSkuType,skuType);
        }

       if(!StringUtils.isEmpty(categoryId)){
           wrapper.eq(SkuInfo::getCategoryId,categoryId);
       }

      if(!StringUtils.isEmpty(keyword)){
          wrapper.like(SkuInfo::getSkuName,keyword);
      }
        //3.执行方法
        Page pageModel = baseMapper.selectPage(page, wrapper);

        return pageModel;
    }


    @Autowired
    private SkuAttrValueService attrValueService;

    @Autowired
    private SkuImageService skuImageService;

    @Autowired
    private SkuPosterService skuPosterService;

    @Override
    @Transactional
    public void saveSkuInfo(SkuInfoVo vo) {
        //1.保存sku_Info数据表
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(vo,skuInfo); //将skuInfoVo属性值赋值给skuInfo的同名属性
        baseMapper.insert(skuInfo);
        //2.保存sku_attr_value
        List<SkuAttrValue> skuAttrValueList = vo.getSkuAttrValueList();
        //由于前端并没有传递过来sku_Id的值，需要手动给skuAttrValueList的sku_id赋值
        if(!CollectionUtils.isEmpty(skuAttrValueList)){
            for (SkuAttrValue skuAttrValue : skuAttrValueList) {
                skuAttrValue.setSkuId(skuInfo.getId());
            }
            attrValueService.saveBatch(skuAttrValueList);
        }
        //3.保存sku_image
        List<SkuImage> skuImagesList = vo.getSkuImagesList();
        if(!CollectionUtils.isEmpty(skuImagesList)){
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(skuInfo.getId());
            }
            skuImageService.saveBatch(skuImagesList);
        }

        //4.保存sku_poster
        List<SkuPoster> skuPosterList = vo.getSkuPosterList();
        if(!CollectionUtils.isEmpty(skuPosterList)){
            for (SkuPoster skuPoster : skuPosterList) {
                skuPoster.setSkuId(skuInfo.getId());
            }
            skuPosterService.saveBatch(skuPosterList);
        }
    }

    @Override   //当前参数的id是sku_info中 id列的值
    public SkuInfoVo getSkuInfoById(Integer id) {
        //1.根据sku_info的id查询sku_Info表
        SkuInfo skuInfo = baseMapper.selectById(id);
        //2.查询海报列表
        List<SkuPoster> posterlist= skuPosterService.findPosterListBySkuId(id);
       //3.图片列表
        List<SkuImage> imageList=    skuImageService.findImagesBySkuId(id);
        //4.获取属性列表
        List<SkuAttrValue> attrList= attrValueService.findAttrValuesBySkuId(id);
        //5.将上面的数据封装到SkuInfoVo对象中
        SkuInfoVo vo = new SkuInfoVo();
        BeanUtils.copyProperties(skuInfo,vo);
        vo.setSkuPosterList(posterlist);
        vo.setSkuImagesList(imageList);
        vo.setSkuAttrValueList(attrList);
        return vo;
    }


    @Override
    @Transactional
    public void updateSkuInfo(SkuInfoVo vo) {
        //1.更新sku_info
        SkuInfo skuInfo = new SkuInfo();
        BeanUtils.copyProperties(vo,skuInfo);
        baseMapper.updateById(skuInfo);
        //2.更新sku_attr_value  -先删除后增加
        //2.1 先删除原来某个sku_id的attr_value值
        Long skuId = skuInfo.getId();
        attrValueService.remove(new LambdaQueryWrapper<SkuAttrValue>().eq(SkuAttrValue::getSkuId,skuId));
        //2.2 新增
        List<SkuAttrValue> skuAttrValueList = vo.getSkuAttrValueList();
        if(!CollectionUtils.isEmpty(skuAttrValueList)){  //当属性列表非空时，再添加属性列表的值
            //由于前端并没有给数据表中sku_id和sort的赋值
            int attrsort=1;
            for (SkuAttrValue attrValue : skuAttrValueList) {
                attrValue.setSkuId(skuId);
                attrValue.setSort(attrsort);
                attrsort++;
            }
            attrValueService.saveBatch(skuAttrValueList);
        }

        //3.更新sku_image
        //3.1 删除原来的sku_id对应的图片列表
        skuImageService.remove(new LambdaQueryWrapper<SkuImage>().eq(SkuImage::getSkuId,skuId));
        //2.新增
        List<SkuImage> skuImagesList = vo.getSkuImagesList();//获取前端发送来的新的sku图片列表
        if(!CollectionUtils.isEmpty(skuImagesList)){
            int imagesort=1;
            for (SkuImage skuImage : skuImagesList) {
                skuImage.setSkuId(skuId);
                skuImage.setSort(imagesort++);
            }
            skuImageService.saveBatch(skuImagesList);
        }
        //4.更新sku_poster
        //4.1 删除海报表中原来的数据
        skuPosterService.remove(new LambdaQueryWrapper<SkuPoster>().eq(SkuPoster::getSkuId,skuId));
        //4.2 新增
        List<SkuPoster> skuPosterList = vo.getSkuPosterList();
        if(!CollectionUtils.isEmpty(skuPosterList)){
            for (SkuPoster skuPoster : skuPosterList) {
                skuPoster.setSkuId(skuId);
            }
            skuPosterService.saveBatch(skuPosterList);
        }
    }

    @Autowired
    private RabbitService rabbitService;
    @Override
    @Transactional
    public void publish(Long skuId, Long status) {
        //修改sku_Info表中的publish_status的列值
        //TODO 后续功能中要完成: 当商品上下架时，需要将skuid信息发送给mq和es
        if(status.intValue()==1){
            SkuInfo skuInfo = new SkuInfo();
            skuInfo.setId(skuId);
            skuInfo.setPublishStatus(1);
            baseMapper.updateById(skuInfo);
            //TODO 发送mq消息更新es数据
            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,MqConst.ROUTING_GOODS_UPPER,skuId);
        }else{
            SkuInfo skuInfo = new SkuInfo();
            skuInfo.setId(skuId);
            skuInfo.setPublishStatus(0);
            baseMapper.updateById(skuInfo);
            //TODO 发送mq消息更新es数据
            rabbitService.sendMessage(MqConst.EXCHANGE_GOODS_DIRECT,MqConst.ROUTING_GOODS_LOWER,skuId);
        }

    }

    @Override
    public void check(Long skuId, Long status) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        skuInfo.setCheckStatus(status.intValue());
        baseMapper.updateById(skuInfo);
    }

    @Override
    public void isNewPerson(Long skuId, Long status) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(skuId);
        skuInfo.setIsNewPerson(status.intValue());
        baseMapper.updateById(skuInfo);
    }

    @Override
    public List<SkuInfo> getSkuInfoList(List ids) {
        return baseMapper.selectBatchIds(ids);
    }

    @Override
    public List<SkuInfo> getSkuInfoListBykeyword(String keyword) {
        //实现模糊查
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(SkuInfo::getSkuName,keyword);
        List<SkuInfo> skuInfos = baseMapper.selectList(wrapper);
        return skuInfos;
    }

    @Override  //判断是否是新人
    public List<SkuInfo> getNewPersonSkuinfoList() {
        //条件1: is_new_person=1
        //条件2: 商品状态是上架: publish_status=1
        //条件3: 先根据库存降序排序,只展示前3条
        Page<SkuInfo> page = new Page<>(1,3);
        LambdaQueryWrapper<SkuInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SkuInfo::getIsNewPerson,1);
        wrapper.eq(SkuInfo::getPublishStatus,1);
        wrapper.orderByDesc(SkuInfo::getStock);//根据库存量降序排序
        //执行查询
        Page<SkuInfo> pagemodel = baseMapper.selectPage(page, wrapper);
        return pagemodel.getRecords();
    }

    @Override
    public SkuInfoVo getSkuInfoBySkuId(Long skuid) {
        //1.创建SkuInfoVo对象
        SkuInfoVo skuInfoVo = new SkuInfoVo();
        //2.获取skuInfo的信息-sku_info
        SkuInfo skuInfo = baseMapper.selectById(skuid);
        //3.获取图片列表 -sku_image
        List<SkuImage> imageList = skuImageService.findImagesBySkuId(skuid.intValue());
        //4.获取海报列表 sku_poster
        List<SkuPoster> posterList = skuPosterService.findPosterListBySkuId(skuid.intValue());
        //5.属性集合-sku_attr_value
        List<SkuAttrValue> attrValueList = attrValueService.findAttrValuesBySkuId(skuid.intValue());
        //6.将结果数据封装到SkuInfoVo中
        BeanUtils.copyProperties(skuInfo,skuInfoVo);
        skuInfoVo.setSkuAttrValueList(attrValueList);
        skuInfoVo.setSkuImagesList(imageList);
        skuInfoVo.setSkuPosterList(posterList);

        return skuInfoVo;
    }

    @Autowired
    private RedisTemplate redisTemplate;
    @Override
    public Boolean checkAndLock(List<SkuStockLockVo> skuStockLockVoList, String orderNo) {
        //1.对被锁的集合进行非空校验
        if(CollectionUtils.isEmpty(skuStockLockVoList)){
            throw new SpyxException(ResultCodeEnum.DATA_ERROR);//数据异常
        }
        //2.遍历所有的商品，验库存，并锁定库存
        for (SkuStockLockVo skuStockLockVo : skuStockLockVoList) {
            //校验库存并 锁定库存(库存足够)
            checkLock(skuStockLockVo);
        }
        //3.如果锁定失败的处理方案: 只要有一件商品锁定失败，所有之前成功的都改回到解锁状态
        //3.1 筛选中锁定失败的商品
        if(skuStockLockVoList.stream().anyMatch(skuStockLockVo -> skuStockLockVo.getIsLock()==false)){
            List<SkuStockLockVo> lockSuccessList = skuStockLockVoList.stream()
                    .filter(skuStockLockVo -> skuStockLockVo.getIsLock() == true) //筛选出锁定成功的商品列表
                    .collect(Collectors.toList());
            lockSuccessList.forEach(skuStockLockVo -> {
                //解锁
                baseMapper.unlockStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
            });
            return false;//加锁失败
        }
        //4.加锁成功，需要在redis将加锁的商品列表保存起来
        //key= stock:info:订单no  value=锁定的商品列表
        redisTemplate.opsForValue().set(RedisConst.SROCK_INFO+orderNo,skuStockLockVoList);

        return true;
    }

    @Autowired
    private RedissonClient redissonClient;

    //校验库存并 锁定库存(库存足够)
    private void checkLock(SkuStockLockVo skuStockLockVo) {
        //1.先获取公平锁:公平锁是一种确保多个线程或进程按照请求顺序获取锁的机制，通过维护一个请求队列来实现
        RLock rLock = redissonClient.getFairLock(RedisConst.SKUKEY_PREFIX+skuStockLockVo.getSkuId());// sku:skuid
        //2.启用锁,手动加锁，手动解锁
        rLock.lock();
        //3.被加锁的代码:  3.1检索库存  3.2锁定库存   3.3更新库存
        try{
            //3.1检索库存
           SkuInfo skuInfo=baseMapper.checkStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
           if(skuInfo==null){
               skuStockLockVo.setIsLock(false);//锁定失败
               return;
           }
            // 3.2 锁定库存，返回值表示受影响的行数
           int rows=baseMapper.lockStock(skuStockLockVo.getSkuId(),skuStockLockVo.getSkuNum());
            if(rows==1){
                skuStockLockVo.setIsLock(true);
            }
            // 3.3更新库存

        }finally {
            //4.解锁
            rLock.unlock();
        }

    }

    @Override
    public void deductStock(String orderNo) {
        //1.先从redis中获取锁定的商品iD和商品购买数量
        List<SkuStockLockVo>  skuStockLockVoList
                = (List<SkuStockLockVo>) redisTemplate.opsForValue().get(RedisConst.SROCK_INFO + orderNo);
        //2.校验
        if(CollectionUtils.isEmpty(skuStockLockVoList)){
            return;
        }
        //3.扣减库存
        for (SkuStockLockVo vo : skuStockLockVoList) {
             baseMapper.deductStock(vo.getSkuId(),vo.getSkuNum());
        }
        //4.清除redis中的数据（锁定的库存数据）
        redisTemplate.delete(RedisConst.SROCK_INFO + orderNo);
    }
}








